import os
import random as rd

import pandas
from django.http import HttpResponse, JsonResponse
from django.shortcuts import render

from courseSchedule.models import Courseinfo, Classroombasicinfo, Building, Coursetime, \
    ClassroomuseinfoIf, ClassroomuseinfoJidian, ClassroomuseinfoWaiyu, ClassroomuseinfoJingguan
from courseSchedule.GlobalData import global_var
from courseSchedule.Schedule import generate_schedules
from courseSchedule.Genetic import Genetic
from djangoProject.settings import MEDIA_ROOT


def index(request):
    b_list = Building.objects \
        .all() \
        .values("building_id", "building_name")  # 楼栋
    # 导航栏通用格式
    response = {
        "flag": 0,  # 0-楼栋  1-教室
        "bid": -1,
        "lists": [{
            "title": "楼栋",
            "list": [{
                "name": b["building_name"],
                "bid": b["building_id"]
            } for b in b_list]
        }]
    }

    return render(request, "automatic_class_scheduling.html", response)


def search_building(request):
    try:
        bid = int(request.GET["bid"])
    except:
        return HttpResponse("楼栋id错误")
    try:
        r_list = Classroombasicinfo.objects \
            .filter(building_id=bid) \
            .values("cid", "classroom_name")
    except:
        return HttpResponse("楼栋查询错误")
    if not r_list:
        return HttpResponse("暂无数据")
    # 导航栏
    response = {
        "flag": 1,
        "bid": bid,
        "lists": [{}]
    }
    # 解析楼层
    temp = sorted([r for r in r_list], key=lambda x: x["classroom_name"])  # 教室名排序
    for t in temp:
        f = t["classroom_name"] // 100  # 楼层
        # 跳过空楼层
        while len(response["lists"]) < f:
            response["lists"].append({})
        # 新楼层添加属性
        if "title" not in response["lists"][f - 1].keys():
            response["lists"][f - 1]["title"] = f"{f}楼"
        if "list" not in response["lists"][f - 1].keys():
            response["lists"][f - 1]["list"] = []
        # 追加入导航栏列表
        response["lists"][f - 1]["list"].append({
            "name": t["classroom_name"],
            "cid": t["cid"]
        })

    return render(request, "automatic_class_scheduling.html", response)


n2col = ["", "mon", "tue", "wed", "thu", "fri", "sat", "sun"]  # 列转星期


def search_room(request):
    # 检错
    try:
        bid = int(request.POST["bid"])
        cid = int(request.POST["cid"])
    except:
        return JsonResponse({
            "code": 0,
            "flag": "教室id错误"
        })
    # 查询课表
    times = Coursetime.objects \
        .filter(building_id=bid, cid=cid) \
        .values("course_id", "building_id", "cid", "first_week", "last_week", "day", "time")
    data = [
        {"week": "第一节"}, {"week": "第二节"}, {"week": "第三节"},
        {"week": "第四节"}, {"week": "第五节"}, {"week": "第六节"}
    ]
    for t in times:
        c = Courseinfo.objects.filter(course_id=t["course_id"]).values("course_name")
        if n2col[t["day"]] not in data[t["time"] - 1].keys():  # 初次写入
            data[t["time"] - 1][n2col[t["day"]]] = ""
            s = f"{c[0]['course_name']}<br>"
        else:
            s = f"<br><br>{c[0]['course_name']}<br>"  # 追加写入
        s += f"{t['first_week']}周" if t["first_week"] == t["last_week"] \
            else f"({t['first_week']}-{t['last_week']}周)"  # 区分单周连续周
        data[t["time"] - 1][n2col[t["day"]]] += s

    return JsonResponse({
        "code": 0,
        "flag": 0,
        "data": data
    })


def genetic_scheduling(bid):
    classrooms = Classroombasicinfo.objects \
        .filter(building_id=bid) \
        .values("cid", "capacity", "attribute")
    courses = Courseinfo.objects \
        .filter(class_id=bid) \
        .values("course_id", "course_type", "course_name", "course_volume", "period", "teacher_id")
    use_info = (ClassroomuseinfoIf, ClassroomuseinfoJidian, ClassroomuseinfoJingguan, ClassroomuseinfoWaiyu)[bid - 1]
    # 普通教室和课程
    r_normal = [r for r in list(classrooms) if r["attribute"] == "阶梯教室"]
    rd.shuffle(r_normal)
    c_normal = [c for c in list(courses) if c["course_type"] != "实验"]
    c_normal.sort(key=lambda x: x["teacher_id"])  # 教师id排序
    # 实验室和实验课
    r_laboratory = [r for r in list(classrooms) if r["attribute"] == "实验室"]
    rd.shuffle(r_laboratory)
    c_laboratory = [c for c in list(courses) if c["course_type"] == "实验"]
    c_laboratory.sort(key=lambda x: x["teacher_id"])  # 教师id排序
    for i in range(2):
        # 分别排普通和实验课
        r = r_normal if i == 0 else r_laboratory
        c = c_normal if i == 0 else c_laboratory
        room_begin, room_limit = 0, min(5, len(r))  # 每次排课教室数量
        course_begin = 0  # 每次排课课程数量
        while course_begin < len(c):
            if room_begin >= len(r):  # 超出排课能力
                return False
            global_var["rooms"] = [{
                "room_id": room["cid"],
                "capacity": room["capacity"]
            } for room in r[room_begin:room_begin + room_limit]]  # 更新教室列表
            # 划分教师id
            room_begin += room_limit
            course_limit = room_limit * 10
            while course_begin + course_limit < len(c) \
                    and c[course_begin + course_limit]["teacher_id"] \
                    == c[course_begin + course_limit - 1]["teacher_id"]:
                course_limit += 1
            # 生成课程时间列表
            schedules = generate_schedules(c[course_begin:course_begin + course_limit])
            course_begin += course_limit
            genetic = Genetic(30, 0.03, 5, 1000)
            genetic.init_population(schedules)  # 初始种群
            res = genetic.evolution()  # 进化
            if res is None:  # 排课失败
                return False
            for s in res:  # 写入数据库
                Coursetime.objects \
                    .create(course_id=s.course_id, building_id=bid, cid=s.room_id, first_week=s.first_week,
                            last_week=s.first_week + s.week_period - 1, day=s.day, time=s.time)
                for w in range(s.first_week, s.first_week + s.week_period):
                    use_info.objects \
                        .filter(cid=s.room_id, week=w, day=s.day, time=s.time) \
                        .update(state=3)
    return True


def schedule(request):
    try:
        bid = int(request.POST["bid"])
    except:
        return JsonResponse({"flag": "楼栋id错误"})
    file = request.FILES.get('file')
    # 检测文件类型格式
    if file.name[-5:] != ".xlsx":
        return JsonResponse({"flag": "文件格式错误"})
    # 保存上传文件
    filename = os.path.join(MEDIA_ROOT, f"{bid}_course_info" + file.name[-5:]).replace('\\', '/')
    with open(filename, 'wb') as f:
        f.write(file.read())
    # 打开excel
    df = pandas.read_excel(filename, header=None)
    rows = df.shape[0]
    # 更新课程数据
    Courseinfo.objects.filter(class_id=bid).delete()
    use_info = (ClassroomuseinfoIf, ClassroomuseinfoJidian, ClassroomuseinfoJingguan, ClassroomuseinfoWaiyu)[bid - 1]
    use_info.objects.update(state=1)
    for i in range(rows):
        if df.iloc[i, 9] == bid:
            Courseinfo.objects.create(course_id=df.iloc[i, 0], course_name=df.iloc[i, 1],
                                      course_number=df.iloc[i, 2], course_type=df.iloc[i, 3],
                                      course_volume=df.iloc[i, 4], credit=df.iloc[i, 5],
                                      period=df.iloc[i, 6], college=df.iloc[i, 7],
                                      teacher_id=df.iloc[i, 8], class_id=df.iloc[i, 9])
    # 删除原始课程时间
    Coursetime.objects.filter(building_id=bid).delete()
    # 排课
    if not genetic_scheduling(bid):
        return JsonResponse({"flag": "排课失败"})

    return JsonResponse({"flag": 0})


def show_table(request):
    cids = Courseinfo.objects \
        .filter(teacher_id=request.GET["id"]) \
        .values("course_id", "course_name")  # 讲授课程id
    times = []  # 课程时间
    # 楼号对应楼栋
    buildings = Building.objects.all().values("building_id", "building_name")
    b_name = {}
    for b in buildings:
        b_name[b["building_id"]] = b["building_name"]
    for cid in cids:
        time = Coursetime.objects \
            .filter(course_id=cid["course_id"]) \
            .values("building_id", "cid", "first_week", "last_week", "day", "time")
        time = list(time)
        for t in time:
            t["course_name"] = cid["course_name"]
            t["building_name"] = b_name[t["building_id"]]
            t["classroom_name"] = Classroombasicinfo.objects \
                .filter(building_id=t["building_id"], cid=t["cid"]) \
                .values("classroom_name")[0]["classroom_name"]
        times += time
    table = [["" for i in range(8)] for j in range(6)]  # 课程表
    # 第一列
    table[0][0] = "第一节"
    table[1][0] = "第二节"
    table[2][0] = "第三节"
    table[3][0] = "第四节"
    table[4][0] = "第五节"
    table[5][0] = "第六节"
    # 根据课程时间填充表格
    for t in times:
        if table[t["time"] - 1][t["day"]] == "":  # 初次写入
            s = f"{t['course_name']}<br>"
        else:  # 追加写入
            s = f"<br><br>{t['course_name']}<br>"
        s += f"{t['first_week']}周" if t["first_week"] == t["last_week"] \
            else f"({t['first_week']}-{t['last_week']}周)"  # 区分单周连续周
        s += f"<br>{t['building_name']} {t['classroom_name']}"
        table[t["time"] - 1][t["day"]] += s
    return render(request, 'course_table.html', {"table": table})

# import os
#
# import pandas
# from django.http import HttpResponse, JsonResponse
# from django.shortcuts import render
#
# from courseSchedule.models import Courseinfo, Classroombasicinfo, Building, Coursetime
# from courseSchedule.GlobalData import global_var
# from courseSchedule.Schedule import generate_schedules
# from courseSchedule.Genetic import Genetic
# from djangoProject.settings import MEDIA_ROOT
#
#
# def index(request):
#     b_list = Building.objects \
#         .all() \
#         .values("building_id", "building_name")  # 楼栋
#     # 导航栏通用格式
#     response = {
#         "flag": 0,  # 0-楼栋  1-教室
#         "bid": -1,
#         "lists": [{
#             "title": "楼栋",
#             "list": [{
#                 "name": b["building_name"],
#                 "bid": b["building_id"]
#             } for b in b_list]
#         }]
#     }
#
#     return render(request, "automatic_class_scheduling.html", response)
#
#
# def search_building(request):
#     try:
#         bid = int(request.GET["bid"])
#     except:
#         return HttpResponse("楼栋id错误")
#     try:
#         r_list = Classroombasicinfo.objects \
#             .filter(building_id=bid) \
#             .values("cid", "classroom_name")
#     except:
#         return HttpResponse("楼栋查询错误")
#     if not r_list:
#         return HttpResponse("暂无数据")
#     # 导航栏
#     response = {
#         "flag": 1,
#         "bid": bid,
#         "lists": [{}]
#     }
#     # 解析楼层
#     temp = sorted([r for r in r_list], key=lambda x: x["classroom_name"])  # 教室名排序
#     for t in temp:
#         f = t["classroom_name"] // 100  # 楼层
#         # 跳过空楼层
#         while len(response["lists"]) < f:
#             response["lists"].append({})
#         # 新楼层添加属性
#         if "title" not in response["lists"][f - 1].keys():
#             response["lists"][f - 1]["title"] = f"{f}楼"
#         if "list" not in response["lists"][f - 1].keys():
#             response["lists"][f - 1]["list"] = []
#         # 追加入导航栏列表
#         response["lists"][f - 1]["list"].append({
#             "name": t["classroom_name"],
#             "cid": t["cid"]
#         })
#
#     return render(request, "automatic_class_scheduling.html", response)
#
#
# n2col = ["", "mon", "tue", "wed", "thu", "fri", "sat", "sun"]  # 列转星期
#
#
# def search_room(request):
#     # 检错
#     try:
#         bid = int(request.POST["bid"])
#         cid = int(request.POST["cid"])
#     except:
#         return JsonResponse({
#             "code": 0,
#             "flag": "教室id错误"
#         })
#     # 查询课表
#     times = Coursetime.objects \
#         .filter(building_id=bid, cid=cid) \
#         .values("course_id", "building_id", "cid", "first_week", "last_week", "day", "time")
#     data = [
#         {"week": "第一节"}, {"week": "第二节"}, {"week": "第三节"},
#         {"week": "第四节"}, {"week": "第五节"}, {"week": "第六节"}
#     ]
#     for t in times:
#         c = Courseinfo.objects.filter(course_id=t["course_id"]).values("course_name")
#         if n2col[t["day"]] not in data[t["time"] - 1].keys():  # 初次写入
#             data[t["time"] - 1][n2col[t["day"]]] = ""
#             s = f"{c[0]['course_name']}<br>"
#         else:
#             s = f"<br><br>{c[0]['course_name']}<br>"  # 追加写入
#         s += f"{t['first_week']}周" if t["first_week"] == t["last_week"] \
#             else f"({t['first_week']}-{t['last_week']}周)"  # 区分单周连续周
#         data[t["time"] - 1][n2col[t["day"]]] += s
#
#     return JsonResponse({
#         "code": 0,
#         "flag": 0,
#         "data": data
#     })
#
#
# def genetic_scheduling(bid):
#     classrooms = Classroombasicinfo.objects \
#         .filter(building_id=bid) \
#         .values("cid", "capacity", "attribute")
#     courses = Courseinfo.objects \
#         .filter(class_id=bid) \
#         .values("course_id", "course_type", "course_name", "course_volume", "period", "teacher_id")
#     # 普通教室和课程
#     r_normal = [r for r in list(classrooms) if r["attribute"] == "阶梯教室"]
#     c_normal = [c for c in list(courses) if c["course_type"] != "实验"]
#     # 实验室和实验课
#     r_laboratory = [r for r in list(classrooms) if r["attribute"] == "实验室"]
#     c_laboratory = [c for c in list(courses) if c["course_type"] == "实验"]
#     for i in range(2):
#         # 分别排普通和实验课
#         r = r_normal if i == 0 else r_laboratory
#         c = c_normal if i == 0 else c_laboratory
#         room_begin, room_limit = 0, 5  # 每次排课教室数量
#         course_begin, course_limit = 0, 50  # 每次排课课程数量
#         while course_begin < len(c):
#             global_var["rooms"] = [{
#                 "room_id": room["cid"],
#                 "capacity": room["capacity"]
#             } for room in r[room_begin:room_begin + room_limit]]  # 更新教室列表
#             room_begin += room_limit
#             schedules = generate_schedules(c[course_begin:course_begin + course_limit])  # 生成课程时间列表
#             course_begin += course_limit
#             genetic = Genetic(30, 0.01, 10, 1000)
#             genetic.init_population(schedules)  # 初始种群
#             res = genetic.evolution()  # 进化
#             if res is None:  # 排课失败
#                 return False
#             for s in res:  # 写入数据库
#                 Coursetime.objects \
#                     .create(course_id=s.course_id, building_id=bid, cid=s.room_id, first_week=s.first_week,
#                             last_week=s.first_week + s.week_period - 1, day=s.day, time=s.time)
#     return True
#
#
# def schedule(request):
#     try:
#         bid = int(request.POST["bid"])
#     except:
#         return JsonResponse({"flag": "楼栋id错误"})
#     file = request.FILES.get('file')
#     # 检测文件类型格式
#     if file.name[-5:] != ".xlsx":
#         return JsonResponse({"flag": "文件格式错误"})
#     # 保存上传文件
#     filename = os.path.join(MEDIA_ROOT, f"{bid}_course_info" + file.name[-5:]).replace('\\', '/')
#     with open(filename, 'wb') as f:
#         f.write(file.read())
#     # 打开excel
#     df = pandas.read_excel(filename, header=None)
#     rows = df.shape[0]
#     # 更新课程数据
#     Courseinfo.objects.filter(class_id=bid).delete()
#     for i in range(rows):
#         if df.iloc[i, 9] == bid:
#             Courseinfo.objects.create(course_id=df.iloc[i, 0], course_name=df.iloc[i, 1],
#                                       course_number=df.iloc[i, 2], course_type=df.iloc[i, 3],
#                                       course_volume=df.iloc[i, 4], credit=df.iloc[i, 5],
#                                       period=df.iloc[i, 6], college=df.iloc[i, 7],
#                                       teacher_id=df.iloc[i, 8], class_id=df.iloc[i, 9])
#     # 删除原始课程时间
#     Coursetime.objects.filter(building_id=bid).delete()
#     # 排课
#     if not genetic_scheduling(bid):
#         return JsonResponse({"flag": "排课失败"})
#
#     return JsonResponse({"flag": 0})
